﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Xml.Linq;
using ExpressionSerialization;
using RemoteQueryService;

namespace TestHarness
{
    static class Walkthrough
    {
        // Very simple serialization example
        public static void BasicExpressionSerialization()
        {
            Console.WriteLine("BASIC SAMPLE - Serialize/Deserialize Simple Expression:");

            Expression<Func<int, int, int>> addExpr = (x, y) => x + y;
            ExpressionSerializer serializer = new ExpressionSerializer();
            XElement addXml = serializer.Serialize(addExpr);
            Expression<Func<int,int,int>> addExpResult = serializer.Deserialize<Func<int,int,int>>(addXml);
            Func<int, int, int> addExpResultFunc = addExpResult.Compile();
            int result = addExpResultFunc(1, 2);  // evaluates to 3

            Console.WriteLine("Deserialized Expression Tree:");
            Console.WriteLine(" " + addExpResult.ToString());
            Console.WriteLine();
        }

        // Serializing an expression tree representing a query expression
        public static void ComplexExpressionSerializationSamples()
        {
            Console.WriteLine("COMPLEX SAMPLE - Serialize/Deserialize In-Memory Query Expression:");

            Expression<Func<IEnumerable<int>>> queryExp = () => from i in Enumerable.Range(1, 10)
                                                                where i % 2 == 0
                                                                select i * i;

            ExpressionSerializer serializer = new ExpressionSerializer();
            XElement queryXml = serializer.Serialize(queryExp);
            Expression<Func<IEnumerable<int>>> queryExpResult = serializer.Deserialize<Func<IEnumerable<int>>>(queryXml);

            // Print out the expression tree: "(x, y) => x + y"
            Console.WriteLine("Deserialized Expression Tree:");
            Console.WriteLine(" " + queryExpResult.ToString());

            // Call it
            Func<IEnumerable<int>> f = queryExpResult.Compile();
            IEnumerable<int> result = f();
            Console.WriteLine("\nResults: ");
            result.ToList().ForEach(n => Console.WriteLine(" " + n));
            Console.WriteLine();
        }

        // Example of scenario such as storing a query in a database and retreiving it 
        // later into the same object model.
        public static void DLinqQuerySerializationSamples()
        {
            Console.WriteLine("DLINQ BASIC SAMPLE - Single Object Model used on both sides of serialization:");

            // Write the query against RemoteTable<Customer>, a dummy implementation 
            // of IQueryable
            RemoteTable<Customer> customers = new RemoteTable<Customer>();
            var query = from c in customers
                        where c.City == "London"
                        select new {c.CompanyName,c};

            XElement queryXml = query.SerializeQuery();

            // On the other side - create a new DataContext, and deserialize 
            // the query xml into a query against this datacontext
            NorthwindDataContext dbOther = new NorthwindDataContext();
            IQueryable queryAfter = dbOther.DeserializeQuery(queryXml);

            // Print out the IQueryable: "(x, y) => x + y"
            Console.WriteLine("Deserialized IQueryable:");
            Console.WriteLine(" " + queryAfter.ToString());

            Console.WriteLine("\n Results: ");
            queryAfter.Cast<object>().ToList().ForEach(n => Console.WriteLine(" " + n.ToString()));
            Console.WriteLine();
        }

        // Example of querying using LINQ against a LINQ to SQL implementation hidden behind a WCF service
        // Note that no database is being directly referenced - all types and calls are proxies generated by 
        // the service reference.
        public static void AcrossTheWireSerializationSamples()
        {
            Console.WriteLine("DLINQ ACROSS THE WIRE SAMPLE - Query against an IQueryable wrapper over a web service:");

            // Query is against a RemoteTable which is a proxy for the the WCF service which executes the DLinq query
            // on the server.  Note that the elements are the service-reference generated types that align with the 
            // DLinq mapping types via the DataContracts.

            var queryService = new RemoteTable<RemoteQueryService.ServiceReference.Customer>();
            var query = from c in queryService
                        where c.City == "London"
                        orderby c.CustomerID
                        select (from o in c.Orders
                                orderby o.OrderDate
                                select o.OrderDate).First();

            Console.WriteLine("\n Query Results: ");
            foreach (var c in query)
                Console.WriteLine(" " + c.Value.ToShortDateString());
        }

    }
}
